#include "HtmlTree.h"

using namespace kc_sf;

HtmlTree::HtmlTree() {
	ht_root = new Node<HtmlTag> (HtmlTag("root")); // specjalny węzeł - korzeń
	ht_act_node = ht_root;
}

HtmlTree::HtmlTree(const HtmlTag &tag) {
	ht_root = new Node<HtmlTag> (HtmlTag("root")); // specjalny węzeł - korzeń
	addNode(tag);
}

HtmlTree::HtmlTree(const HtmlTree &tree) {
	ht_root = new Node<HtmlTag> (HtmlTag("root"));
	ht_act_node = ht_root;
	for (unsigned int i = 0; i < tree.ht_root->childrenNr(); ++i) {
		copyNodeAndChildren(tree.ht_root->child(i));
	}
}

HtmlTree & HtmlTree::operator=(const HtmlTree &tree) {
	ht_root = new Node<HtmlTag> (HtmlTag("root"));
	ht_act_node = ht_root;
	for (unsigned int i = 0; i < tree.ht_root->childrenNr(); ++i) {
		copyNodeAndChildren(tree.ht_root->child(i));
	}

	return *this;
}

// ----------- //

HtmlTree::~HtmlTree() {
	ht_root->deleteChildren();
	if (ht_root != NULL)
		delete ht_root;
}

/**
 * Zwraca false w 2óch przypadkach:
 * - tag, który musi posiadać rodzica (zawartość lub tag zamykający) posiada go
 * - tag zamykający kończy nieprawidłowy tag otwierający
 */
bool HtmlTree::addNode(const HtmlTag &child) {
	bool success = false;

	if (ht_root == NULL)
		throw std::runtime_error("HtmlTree.cpp. addNode. Root == NULL");

	if (ht_act_node == ht_root) { // najwyższy poziom
		if (!child.isCloseTag()) { // <tag> | <tag/>
			ht_act_node->addChild(child);
			ht_act_node = &(ht_act_node->child(ht_act_node->childrenNr() - 1));
			success = true;
		} // else - błąd - nie posiada rodzica czyli <tag>
	} else {
		if (child.isCloseTag()) { // </znacznik> - nic nie rob tylko przejdz poziom wyzej
			if ((ht_act_node)->get().name() == child.name()) { // sprawdź czy rodzic się zgadza
				ht_act_node = ht_act_node->parent();
				success = true;
			}
		} else {
			ht_act_node->addChild(child);
			if (child.isOpenTag()) {
				ht_act_node = &(ht_act_node->child(ht_act_node->childrenNr()
						- 1));
			}
			success = true;
		}
	}
	return success;
}

bool HtmlTree::addContent(const std::string &content) {
	if (ht_root == NULL)
		throw std::runtime_error("HtmlTree.cpp. addNode. Root == NULL");

	if (ht_act_node == NULL)
		throw std::runtime_error("HtmlTree.cpp. addNode. act_node == NULL");

	if (ht_act_node != ht_root) {
		ht_act_node->get().addTextContent(content);
		return true;
	}
	return false;
}

void HtmlTree::deleteActNodeChildrenNodes() {
	ht_act_node->deleteChildren();
}

// ---------------------------- //

void HtmlTree::copyNodeAndChildren(const Node<HtmlTag> &node) {
	ht_act_node->addChild(node.get());

	if (node.childrenNr() > 0) {
		ht_act_node = &(ht_act_node->child(ht_act_node->childrenNr() - 1));

		for (unsigned int i = 0; i < node.childrenNr(); ++i) {
			copyNodeAndChildren(node.child(i));
		}

		ht_act_node = ht_act_node->parent();
	}
}

std::ostream & HtmlTree::print(std::ostream &out, const Node<HtmlTag> &node,
		int depth) const {
	std::cout.width(depth);
	std::cout.fill('-');
	out << " " << node.get().name() << std::endl;

	++ depth;
	for (unsigned int i = 0; i < node.childrenNr(); ++i) {
		print(out, node.child(i), depth);
	}

	return out;
}

// ---------------------------- //

namespace kc_sf {

std::ostream & operator<<(std::ostream &out, const HtmlTree &tree) {
	tree.print(out, tree.root(), 1);
	return out;
}

}

